package com.fingard.dsp.tcpserver;

import com.fingard.FGBiz;
import com.fingard.constant.Format;
import com.fingard.crypto.SignEncryptHelper;
import com.fingard.diagnostics.LogHelper;
import com.fingard.dsp.DSPSet;
import com.fingard.dsp.Transmit;
import com.fingard.dsp.bank.DealDirectBank;
import com.fingard.dsp.bank.DealTransSeq;
import com.fingard.dsp.bank.dbobj.secretkey.SecretKeyDataHelper;
import com.fingard.dsp.bank.helpers.FileType;
import com.fingard.dsp.bank.reqrespobj.PacketType;
import com.fingard.dsp.bank.reqrespobj.ReqRespHeader;
import com.fingard.dsp.bankset.BankFront;
import com.fingard.dsp.core.DSPSecurityData;
import com.fingard.dsp.core.dao.directchannel.DirectChannelMapper;
import com.fingard.dsp.core.dao.record.DirectCmdRecordMapper;
import com.fingard.dsp.core.dao.record.DspExceptionInfoMapper;
import com.fingard.dsp.core.entity.record.DspExceptionInfoPO;
import com.fingard.dsp.entity.enums.ENDSPResult;
import com.fingard.dsp.entity.po.DirectChannelPO;
import com.fingard.dsp.entity.po.DirectCmdRecordPO;
import com.fingard.io.FileHelper;
import com.fingard.luna.framework.boot.core.util.SpringContextHolder;
import com.fingard.text.StringHelper;
import com.fingard.text.XmlHelper;
import com.fingard.util.AESUtil;
import com.fingard.util.DateHelper;
import com.fingard.xml.XmlTextReader;
import org.apache.commons.codec.binary.Base64;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.nio.ByteBuffer;
import java.security.PublicKey;
import java.text.ParseException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 执行处理每个请求，并返回响应
 */
public class ThreadEachReqNIO implements Runnable {

    private RequestNIO reqNIO;
    private BankFront preBankFront = null;
    private BankResetEvent autoResetEvent;
    private PayQryController payQryCtrl;//支付状态查询控制，支付如果还未执行结束，则不允许查询

    public ThreadEachReqNIO(RequestNIO p_req, BankFront p_bankFront, BankResetEvent p_resetEvent, PayQryController pCtrl, int pHttpDistributeType) {
        reqNIO = p_req;
        preBankFront = p_bankFront;
        autoResetEvent = p_resetEvent;
        payQryCtrl = pCtrl;
        httpDistributeType = pHttpDistributeType;
    }

    private String getLogCode() {
        if (reqNIO != null && reqNIO.bankHeader != null) {
            return reqNIO.bankHeader.bankCode + "." + reqNIO.bankHeader.transType;
        } else {
            return "ThreadEachReqNIO";
        }
    }

    public int httpDistributeType;//1 src-->desc //2 desc-->src

    @Override
    public void run() {
        String reqPayID = "";
        boolean needRemove = false;
        try {
            if (preBankFront != null) {
                preBankFront.setLastExecTime(reqNIO.bankHeader);
            }
            boolean isChked = true;//状态查询是否可以发起，即支付处理线程已完成
            if (PacketType.Pay.equals(reqNIO.bankHeader.pckType) || PacketType.PayQuery.equals(reqNIO.bankHeader.pckType)) {
                reqPayID = reqNIO.bankHeader.reqSeqOrBatNo;
                if (StringHelper.hasAnyChar(reqPayID)) {
                    reqPayID = StringHelper.joinNotEmpty("-", reqNIO.bankHeader.tenant, reqNIO.bankHeader.bankCode, reqPayID);
                    if (PacketType.Pay.equals(reqNIO.bankHeader.pckType)) {
                        payQryCtrl.putPayReqID(reqPayID);
                        needRemove = true;//执行完成后，需移除
                    } else {
                        isChked = payQryCtrl.checkNotExistsPayReqID(reqPayID);
                    }
                }
            }
            doRequest(reqNIO, isChked);
        } catch (Exception ex) {
            FGBiz.limitMsg.exception(getLogCode(), ex);
            reqNIO.sbLog.append(LogHelper.getStackTrace(ex));
        } finally {
            if (preBankFront != null) {
                preBankFront.release(reqNIO.bankHeader);
                autoResetEvent.set();
            }
            if (needRemove) {
                payQryCtrl.removePayReqID(reqPayID);
            }
        }
    }


    /**
     * 接收ATS信息入库
     *
     * @param p_bizO
     * @param tmpHeader
     */
    private boolean saveReceivedATSInfoToDB(RequestNIO p_bizO, String tmpRespBody, ReqRespHeader tmpHeader) throws IOException, ParseException {
        DirectCmdRecordMapper recordMapper = SpringContextHolder.getBean(DirectCmdRecordMapper.class);
        DirectChannelMapper directChannelMapper = SpringContextHolder.getBean(DirectChannelMapper.class);
        DirectCmdRecordPO recordPO = new DirectCmdRecordPO();
        Map<String, Object> recordParam = new HashMap<>();
        recordParam.put("transseqid", p_bizO.bankHeader.transSeqID);
        List<DirectCmdRecordPO> cmdRecordPOS = recordMapper.selectByMap(recordParam);
        if (cmdRecordPOS.size() > 0) {
            FGBiz.limitMsg.error(getLogCode() + ".payQryChk", ENDSPResult.COMMAND_RESUBMIT.msg());
            tmpRespBody = "<ATSYH><TransResp><TransParam><RespCode>" + ENDSPResult.COMMAND_RESUBMIT.code() + "</RespCode><RespInfo>" + ENDSPResult.COMMAND_RESUBMIT.msg() + "，请检测是否重复提交指令！</RespInfo></TransParam></TransResp></ATSYH>";
            p_bizO.writeRespBody(false, "", tmpRespBody);
            p_bizO.sbLog.append(Format.DateTimeSSSFormat.format(new Date()) + " 4.返回ATS的报文：\r\n" + tmpRespBody);
            return false;
        }
        recordPO.setUrid(UUID.randomUUID().toString());
        recordPO.setDirectchannelcmd(p_bizO.bankHeader.transType);
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("CODE", p_bizO.bankHeader.bankCode);
        List<DirectChannelPO> directChannelPOS = directChannelMapper.selectByMap(paramMap);
        recordPO.setDirectchannelid(directChannelPOS.get(0).getUrid());
        recordPO.setDspip(FGBiz.localHostIp);
        recordPO.setBankfrontid(preBankFront.urid);
        recordPO.setTransseqid(p_bizO.bankHeader.transSeqID);
        recordPO.setCreatedby("");
        recordPO.setLastmodifiedby("");
        Date date = new Date();
        recordPO.setCreatedon(date);
        recordPO.setRequesttime(Format.DateTime14Format.parse(tmpHeader.transTime));
        recordPO.setLastmodifiedon(date);
        if (PacketType.Pay.equals(reqNIO.bankHeader.pckType)) {
            recordPO.setCommandcode(p_bizO.bankHeader.commandCode);
        }
        if (StringHelper.isNullOrEmpty(p_bizO.bankHeader.tenant)) {
            recordPO.setTenantid(null);
        } else {
            recordPO.setTenantid(p_bizO.bankHeader.tenant);
        }
        recordPO.setRowversion(1);
        recordMapper.insert(recordPO);
        return true;
    }

    Pattern respCodePattern = Pattern.compile("<RespCode>(.*?)</RespCode>");

    /**
     * 更新返回ATS信息
     *
     * @param tmpRespBody
     * @param p_bizO
     * @param preBankFront
     * @param logFilePath
     */
    private void updateResponseATSInfoToDB(String tmpRespBody, RequestNIO p_bizO, BankFront preBankFront, String logFilePath) {
        DirectCmdRecordMapper recordMapper = SpringContextHolder.getBean(DirectCmdRecordMapper.class);
        Map<String, Object> paramMap = new HashMap<>(1);
        paramMap.put("transseqid", p_bizO.bankHeader.transSeqID);
        List<DirectCmdRecordPO> recordPO = recordMapper.selectByMap(paramMap);
        if (recordPO == null || recordPO.size() != 1) {
            return;
        }
        Matcher respCodeMatcher = respCodePattern.matcher(tmpRespBody);
        String respcode = "";
        String respInfo = "";
        while (respCodeMatcher.find()) {
            respcode = respCodeMatcher.group(1);
        }
        if (tmpRespBody.indexOf("<RespInfo>") != -1) {
            respInfo = tmpRespBody.substring(tmpRespBody.indexOf("<RespInfo>") + 10, tmpRespBody.indexOf("</RespInfo>"));
        }
        DirectCmdRecordPO selectedPo = recordPO.get(0);
        Date date = new Date();
        selectedPo.setBankfrontid(preBankFront.urid);
        selectedPo.setLastmodifiedon(date);
        selectedPo.setResponsetime(date);
        selectedPo.setRespcode(respcode);
        selectedPo.setBanklogsfilepath(logFilePath);
        recordMapper.updateById(selectedPo);
        //保存错误信息
        if (!"0".equals(respcode)) {
            DspExceptionInfoMapper exceptionInfoMapper = SpringContextHolder.getBean(DspExceptionInfoMapper.class);
            DspExceptionInfoPO exceptionInfoPO = new DspExceptionInfoPO();
            exceptionInfoPO.setUrid(UUID.randomUUID().toString());
            exceptionInfoPO.setDirectcmdid(recordPO.get(0).getUrid());
            if (respInfo.length() > 1024) {
                respInfo = respInfo.substring(0, 1023);
            }
            exceptionInfoPO.setExceptioninfo(respInfo);
            exceptionInfoPO.setExceptiontype(respcode);
            exceptionInfoMapper.insert(exceptionInfoPO);
        }


    }

    private void doRequest(RequestNIO p_bizO, boolean pIsChked) {
        String tmpRespBody = "";
        ReqRespHeader tmpHeader = p_bizO.bankHeader;
        SocketReceiver tmpReceiver = reqNIO.reqSocketReceiver;

        try {
            boolean isRtnFileBytes = false;
            boolean isRunJAVAversion = false;
//            if (!DSPSecurityData.getInstance().isReadFileFlag()) {
//                boolean result = saveReceivedATSInfoToDB(p_bizO, tmpRespBody, tmpHeader);
//                if (!result) {
//                    LogHelper.writeBankLog(p_bizO.seqIDInner, p_bizO.connTime, new Date(), "", tmpHeader, p_bizO.sbLog, false);
//                    return;
//                }
//            }
            String rtnFilePath = "";
            //上线切换检测
            String startJAVAversionDate = FGBiz.dspCenter.dspConfig.getValueAsString("startJAVAversionDate");

            String clientReqStr = "";
            if (StringHelper.hasAnyChar(p_bizO.xmlData)) {
                clientReqStr = p_bizO.xmlData;
            } else {
                clientReqStr = new String(tmpReceiver.reqBytes, tmpReceiver.contentStartIndex, tmpReceiver.contentLength, tmpReceiver.charsetName);
            }
            if (StringHelper.hasAnyChar(startJAVAversionDate) && clientReqStr != null) {
                //明细流水，电子回单的开始日期不得早于配置的日期
                XmlTextReader retReader = new XmlTextReader(clientReqStr);
                //             String transType = retReader.getFirstText("/ATSYH/TransReq/TransType");
                //回单任务
                if ("7516".equalsIgnoreCase(tmpHeader.transType) || "7515".equalsIgnoreCase(tmpHeader.transType) || "DOWNLOADRECEIPT".equalsIgnoreCase(tmpHeader.transType)) {
                    String startDate = retReader.getFirstText("/ATSYH/TransReq/TransParam/DetailRecord/DateFrom");
                    if (StringHelper.isNullOrEmpty(startDate)) {
                        startDate = retReader.getFirstText("/ATSYH/TransReq/TransParam/DateFrom");
                    }
                    if (StringHelper.hasAnyChar(startDate)) {
                        if (DateHelper.compareDay(Format.Date8Format.parse(startDate), Format.Date8Format.parse(startJAVAversionDate)) < 0) {
                            isRunJAVAversion = true;
                        }
                    }
                }
            }
            if (pIsChked == false) {
                tmpRespBody = "支付请求流水号" + tmpHeader.reqSeqOrBatNo + "还未处理结束，暂不能发起查询";
                FGBiz.limitMsg.error(getLogCode() + ".payQryChk", tmpRespBody);
                tmpRespBody = "<ATSYH><TransResp><TransParam><RespCode>-1</RespCode><RespInfo>" + tmpRespBody + "</RespInfo></TransParam></TransResp></ATSYH>";
            } else if (isRunJAVAversion) {
                FGBiz.limitMsg.warning("acceptByNewIO", "JAVA版本上线日期不能晚于当前指令的查询日期");
                tmpRespBody = "<ATSYH><TransResp><TransParam><RespCode>-1</RespCode><RespInfo>JAVA版本上线日期不能晚于当前指令的查询日期</RespInfo></TransParam></TransResp></ATSYH>";
            } else if (tmpReceiver.isSyncFile) {
                tmpRespBody = "<ATSYH><TransResp><TransParam><RespCode>" + tmpReceiver.syncCode + "</RespCode><RespInfo>" + XmlHelper.encode(tmpReceiver.syncMsg) + "</RespInfo></TransParam></TransResp></ATSYH>";
            } else if ("savetodb".equals(tmpReceiver.action)) {
                tmpRespBody = "<ATSYH><TransResp><TransParam><RespCode>-1</RespCode><RespInfo>程序入口有误</RespInfo></TransParam></TransResp></ATSYH>";
            } else if ("getfile".equals(tmpReceiver.action)) {
                String oriFile = DSPSet.replaceFilePath(tmpReceiver.oriFilePath);
                String errmsg = "";
                if (FileType.dataFile.toLowerCase().equals(tmpReceiver.fileType)) {
                    oriFile = StringHelper.trimEndFileSp(FGBiz.dspCenter.dspSet.dataDirPath) + File.separator + StringHelper.trimStartFileSp(oriFile);
                }
                if (StringHelper.hasAnyChar(oriFile)) {
                    if (FileHelper.existFile(oriFile)) {
                        isRtnFileBytes = true;
                        rtnFilePath = oriFile;
                    } else {
                        errmsg = "文件" + tmpReceiver.oriFilePath + "不存在";
                    }
                } else {
                    errmsg = "请求参数文件路径为空";
                }
                if (!isRtnFileBytes) {
                    tmpRespBody = "<ATSYH><TransResp><TransParam><RespCode>-1</RespCode><RespInfo>" + XmlHelper.encode(errmsg) + "</RespInfo></TransParam></TransResp></ATSYH>";
                }
            } else if (p_bizO.isHttpDistribute) {//http分发
                p_bizO.reqSocketReceiver.clientSocketChannel.configureBlocking(true);
                p_bizO.transmit.doHttpDistribute(p_bizO.reqSocketReceiver.getRowReqString(p_bizO.transmit.getCharset()), this.httpDistributeType);
            } else if (tmpReceiver.contentStartIndex >= 0 || reqNIO.request != null) {
                try {
                    boolean isChecked = false;
                    if (FGBiz.dspCenter.enableCheckTransSeqID && !StringHelper.isNullOrEmpty(tmpHeader.transTime)) {
                        Date transTime = null;
                        // 兼容TransTime格式为：yyyyMMddHH:mm:ss
                        if (tmpHeader.transTime.indexOf(" ") > 0) {
                            transTime = Format.DateTimeFormat.parse(tmpHeader.transTime);
                        } else {
                            transTime = Format.DateTime1Format.parse(tmpHeader.transTime);
                        }

                        Date currDate = new Date();
                        if (Math.abs(DateHelper.getDifferMins(transTime, currDate)) > DealTransSeq.maxStep) {
                            tmpRespBody = "<ATSYH><TransResp><TransParam><RespCode>-1</RespCode><RespInfo>本次请求时间距离当前时间太长，请求已过期！</RespInfo></TransParam></TransResp></ATSYH>";
                        } else {
                            isChecked = true;
                        }
                    } else {
                        isChecked = true;
                    }
                    if (isChecked) {
                        boolean isUniqueTransSeq = true;
                        if (FGBiz.dspCenter.enableCheckTransSeqID) {
                            if (!DealTransSeq.addTransSeq(tmpHeader.transSeqID, tmpHeader.transTime)) {
                                isUniqueTransSeq = false;
                                tmpRespBody = "<ATSYH><TransResp><TransParam><RespCode>-1</RespCode><RespInfo>指令流水号重复</RespInfo></TransParam></TransResp></ATSYH>";
                            }
                        }
                        if (isUniqueTransSeq) {
                            Transmit tmpTransmit = new Transmit(p_bizO, FGBiz.dspCenter.rootDirPath);
                            if (tmpTransmit.isTransmit(tmpHeader)) {
                                //判断客户公钥是否存在来决定转发加密
                                if (FGBiz.dspCenter.dspSet.enableEncrypt && tmpTransmit.publicKey != null) {
                                    p_bizO.sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + " " + p_bizO.seqIDInner + " " + "当前客户【" + tmpHeader.tenant + "】配置了加密转发：\r\n");
                                    Date date = new Date();
                                    //判断数据是否需要加密
                                    boolean isEncryt = StringHelper.isNullOrEmpty(tmpTransmit.destUrl) || !tmpTransmit.destUrl.startsWith("https:");
                                    //组装加密和签名数据
                                    String aeskey = "";
                                    if (isEncryt) {
                                        aeskey = getAESKeyByTenant(tmpHeader.tenant, date, p_bizO, tmpTransmit);
                                        tmpRespBody = dataSignOrEncrypt(p_bizO.clientReqStr, aeskey, date, p_bizO, tmpTransmit.charset);
                                    } else {
                                        tmpRespBody = dataSignOrEncrypt(p_bizO.clientReqStr, "", date, p_bizO, tmpTransmit.charset);
                                    }
                                    p_bizO.sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + " " + p_bizO.seqIDInner + " " + "转发的加密报文：\r\n" + tmpRespBody + "\r\n");
                                    tmpRespBody = tmpTransmit.doTransmit(tmpRespBody.getBytes(tmpTransmit.charset));
                                    p_bizO.sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + " " + p_bizO.seqIDInner + " " + "转发返回的响应报文\r\n" + tmpRespBody + "\r\n");

                                    //通过数据解密或者报文截取获取明文
                                    try {
                                        String respPlain = "";
                                        if (isEncryt) {
                                            respPlain = dataDecrypt(tmpRespBody, aeskey, p_bizO, tmpTransmit.charset);
                                        } else {
                                            respPlain = StringHelper.getTagContext(tmpRespBody, "plain");
                                        }
                                        tmpRespBody = dataVerify(tmpRespBody, respPlain, p_bizO, tmpTransmit.publicKey, tmpTransmit.charset);
                                    } catch (Exception ex) {
                                        ex.getStackTrace();
                                    }
                                } else {
                                    p_bizO.sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + " " + p_bizO.seqIDInner + " " + "当前客户【" + tmpHeader.tenant + "】不需要加密转发：\r\n");
                                    tmpRespBody = tmpTransmit.doTransmit(p_bizO.reqSocketReceiver.getContentBytes());
                                }
                            } else {
                                if (p_bizO.clientReqStr.startsWith("Action:sssmap")) {
                                    StringReader strReader = new StringReader(p_bizO.clientReqStr);
                                    BufferedReader tmpReader = new BufferedReader(strReader);

                                    HashMap<String, String> hashParams = new HashMap<String, String>();
                                    while (true) {
                                        String eachline = tmpReader.readLine();
                                        if (eachline == null) {
                                            break;
                                        }

                                        String separator = "";
                                        if (eachline.indexOf("=") > 0 && eachline.indexOf(":") > 0) {
                                            if (eachline.indexOf("=") < eachline.indexOf(":")) {
                                                separator = "=";
                                            } else {
                                                separator = ":";
                                            }
                                        } else if (eachline.indexOf("=") > 0) {
                                            separator = "=";
                                        } else if (eachline.indexOf(":") > 0) {
                                            separator = ":";
                                        }
                                        int index = eachline.indexOf(separator);
                                        if (index >= 0) {
                                            String key = eachline.substring(0, eachline.indexOf(separator));
                                            String value = eachline.substring(eachline.indexOf(separator) + 1);
                                            hashParams.put(key, value.trim());
                                        }
                                    }
                                    if (tmpReader != null) {
                                        tmpReader.close();
                                    }
                                    if (strReader != null) {
                                        strReader.close();
                                    }

                                    DealDirectBank tmpDealDirect = new DealDirectBank();
                                    HashMap<String, String> retHash = tmpDealDirect.dealDirectTrans(hashParams);
                                    StringBuilder stringBuilder = new StringBuilder();
                                    Iterator<String> iterator = retHash.keySet().iterator();
                                    while (iterator.hasNext()) {
                                        String key = iterator.next();
                                        stringBuilder.append(key + ":" + retHash.get(key) + "\r\n");
                                    }
                                    tmpRespBody = stringBuilder.toString();
                                } else {
                                    DealDirectBank tmpDealDirect = new DealDirectBank(p_bizO.clientReqStr);
                                    tmpDealDirect.setBankFront(preBankFront);
                                    tmpRespBody = tmpDealDirect.dealDirectTrans(p_bizO, tmpHeader, p_bizO.xmlReader);
                                }

                                //根据请求判断数据是否需要签名加密
                                if (p_bizO.reqSocketReceiver.isReqEncrypt || p_bizO.reqSocketReceiver.isReqSign) {
                                    String aeskey = "";
                                    if (p_bizO.reqSocketReceiver.isReqEncrypt) {
                                        SecretKeyDataHelper secretKeyDataHelper = new SecretKeyDataHelper(preBankFront.tenant, p_bizO.keyDate);
                                        aeskey = secretKeyDataHelper.getKey(p_bizO.keyDate);
                                        p_bizO.sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + " " + p_bizO.seqIDInner + " " +
                                                String.format("使用客户【%s】日期【%s】的密钥【%s】进行加密\r\n\r\n", preBankFront.tenant, Format.Date8Format.format(p_bizO.keyDate), aeskey));
                                    }
                                    p_bizO.sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + " " + p_bizO.seqIDInner + "返回ATS的明文:\r\n" + tmpRespBody + "\r\n");
                                    tmpRespBody = dataSignOrEncrypt(tmpRespBody, aeskey, p_bizO.keyDate, p_bizO, p_bizO.reqSocketReceiver.charsetName);
                                }
                            }
                        }
                    }

                } catch (Exception e2) {
                    p_bizO.sbLog.append(LogHelper.getStackTrace(e2) + "\r\n");
                    tmpRespBody = e2.toString();
                } catch (Throwable t3) {
                    p_bizO.sbLog.append(LogHelper.getStackTrace(t3) + "\r\n");
                    tmpRespBody = t3.toString();
                }
            }
            if (p_bizO.isHttpDistribute) {
                p_bizO.transmit.closeHttpDistribute();
                if (p_bizO.reqSocketReceiver.clientSocketChannel != null) {
                    p_bizO.reqSocketReceiver.clientSocketChannel.close();
                    p_bizO.reqSocketReceiver.clientSocketChannel = null;
                }
                return;
            } else {
                if (p_bizO.clientReqStr.startsWith("Action:sssmap")) {
                    if (p_bizO.reqSocketReceiver.readedLength == 0) {
                        //F5等设备的监测
                        p_bizO.reqSocketReceiver.clientSocketChannel.close();
                        p_bizO.reqSocketReceiver.clientSocketChannel = null;
                        return;
                    }
                    byte[] tmpBytesBody = tmpRespBody.getBytes(p_bizO.reqSocketReceiver.charsetName);
                    ByteBuffer writeBuffer = ByteBuffer.wrap(tmpBytesBody);
                    p_bizO.reqSocketReceiver.clientSocketChannel.configureBlocking(true);
                    p_bizO.reqSocketReceiver.clientSocketChannel.write(writeBuffer);
                    p_bizO.isAlreadyWriteResp = true;
                    p_bizO.reqSocketReceiver.clientSocketChannel.close();
                    p_bizO.reqSocketReceiver.clientSocketChannel = null;
                } else {
                    p_bizO.writeRespBody(isRtnFileBytes, rtnFilePath, tmpRespBody);
                }
            }
        } catch (Exception e) {
            FGBiz.limitMsg.exception(getLogCode(), e);
            p_bizO.sbLog.append(LogHelper.getStackTrace(e) + "\r\n");

        } catch (Throwable t2) {
            FGBiz.limitMsg.exception(getLogCode(), t2);
            p_bizO.sbLog.append(LogHelper.getStackTrace(t2) + "\r\n");
        } finally {

            try {

                if (tmpReceiver.clientSocketChannel != null) {
                    tmpReceiver.clientSocketChannel.close();
                }

                if (tmpReceiver.saveFileStream != null) {
                    tmpReceiver.saveFileStream.close();
                }
            } catch (Exception e) {
                FGBiz.limitMsg.exception(getLogCode(), e);
                p_bizO.sbLog.append(LogHelper.getStackTrace(e) + "\r\n");
            }

        }

        try {

            if (p_bizO.isHttpDistribute) {
                p_bizO.transmit.closeHttpDistribute();
                if (p_bizO.reqSocketReceiver.clientSocketChannel != null) {
                    p_bizO.reqSocketReceiver.clientSocketChannel.close();
                    p_bizO.reqSocketReceiver.clientSocketChannel = null;
                }
                return;
            }

            Date logTime = new Date();

            if (!p_bizO.clientReqStr.startsWith("Action:sssmap")) {
                if (tmpReceiver.isSyncFile) {
                    p_bizO.sbLog.append(Format.DateTimeSSSFormat.format(logTime) + " " + p_bizO.seqIDInner + " 4.返回客户端的报文：\r\n");
                } else {
                    p_bizO.sbLog.append(Format.DateTimeSSSFormat.format(logTime) + " 4.返回ATS的报文：\r\n");
                }

                p_bizO.sbLog.append(tmpRespBody);
                p_bizO.sbLog.append("\r\n");
            }

            if (tmpReceiver.isSyncFile) {//是文件同步
                LogHelper.writeBankLogByHour(logTime, "", tmpHeader, p_bizO.sbLog);
            } else {
                //ATSES-22260 供应链直联生成的DSP报文在渠道后面增加经销商编码
                String prefix = "";
                if ("QryFinanceRecInfo".equals(tmpHeader.transType) || "QryQuotaInfo".equals(tmpHeader.transType)) {
                    prefix = p_bizO.xmlReader.getFirstText("/ATSYH/TransReq/TransParam/DealerCode");
                } else if ("QryInCustodyInfo".equals(tmpHeader.transType) || "RetailStockMsg".equals(tmpHeader.transType)
                        || "RetailMsg".equals(tmpHeader.transType) || "QryUndueBillInfo".equals(tmpHeader.transType)
                        || "OrderMsg".equals(tmpHeader.transType) || "CertificateMailedMsg".equals(tmpHeader.transType)
                        || "MailedMsg".equals(tmpHeader.transType) || "QryInCustodyInfo".equals(tmpHeader.transType)) {
                    p_bizO.xmlReader.backToTop();
                    prefix = p_bizO.xmlReader.getFirstText("/ATSYH/TransReq/TransParam/DetailRecord/DealerCode");
                }
                String logFilePath = LogHelper.writeBankLog(p_bizO.seqIDInner, p_bizO.connTime, logTime, prefix, tmpHeader, p_bizO.sbLog, true);
                if (!DSPSecurityData.getInstance().isReadFileFlag()) {
                    updateResponseATSInfoToDB(tmpRespBody, p_bizO, preBankFront, logFilePath);
                }
            }

        } catch (Exception e) {
            FGBiz.limitMsg.exception(getLogCode(), e);
        }
    }


    /**
     * 获取对称密钥
     *
     * @param tenant
     * @param date
     * @param p_bizO
     * @param tmpTransmit
     * @return
     * @throws Exception
     */
    public String getAESKeyByTenant(String tenant, Date date, RequestNIO p_bizO, Transmit tmpTransmit) throws Exception {
        Map<String, String> date_key_map = FGBiz.dspCenter.dspSet.certConfig.aesKeyMap.get(tenant);
        String date8Str = Format.Date8Format.format(date);
        String aeskey = "";
        if (date_key_map == null) {
            //防止并发带来的数据覆盖
            synchronized (FGBiz.dspCenter.dspSet.certConfig.aesKeyMap) {
                date_key_map = FGBiz.dspCenter.dspSet.certConfig.aesKeyMap.get(tenant);
                if (date_key_map == null) {
                    date_key_map = new HashMap<String, String>();
                    FGBiz.dspCenter.dspSet.certConfig.aesKeyMap.put(tenant, date_key_map);
                }
            }
        }
        aeskey = date_key_map.get(date8Str);
        if (StringHelper.isNullOrEmpty(aeskey)) {
            synchronized (date_key_map) {
                aeskey = date_key_map.get(date8Str);
                if (StringHelper.isNullOrEmpty(aeskey)) {
                    if (StringHelper.isNullOrEmpty(aeskey)) {
                        //对数据进行非对称加密
                        String keyobj = tenant + "_" + date8Str;
                        String aesReq = "<KeyObj>" + SignEncryptHelper.doEncryptByRSA2(keyobj.getBytes(tmpTransmit.charset), tmpTransmit.publicKey) + "</KeyObj>";
                        p_bizO.sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + " " + p_bizO.seqIDInner + " 发送密钥请求报文：\r\n" + aesReq + "\r\n");
                        String[] resp = tmpTransmit.getAESKeyHttp(aesReq.getBytes(tmpTransmit.charset));
                        if ("000000".equals(resp[0])) {
                            aeskey = resp[1];
                            date_key_map.put(date8Str, aeskey);
                            //只保留今日或者昨天的对称密钥
                            if (date_key_map.size() >= 3) {
                                Iterator iterator = date_key_map.keySet().iterator();
                                while (iterator.hasNext()) {
                                    String key = (String) iterator.next();
                                    if (key.compareTo(Integer.valueOf(date8Str) - 1 + "") < 0) {
                                        String keyValue = date_key_map.get(key);
                                        p_bizO.sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + " " + p_bizO.seqIDInner + String.format("客户【%s】在日期【%s】的密钥【%s】已过期;", tenant, key, keyValue) + "\r\n");

                                        iterator.remove();
                                        date_key_map.remove(key);
                                        p_bizO.sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + " " + p_bizO.seqIDInner + String.format("客户【%s】在日期【%s】的密钥【%s】移除成功：", tenant, key, keyValue) + "\r\n");
                                    }
                                }
                            }
                        } else {
                            throw new Exception(resp[1]);
                        }
                    }
                }
            }
        }
        p_bizO.sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + " " + p_bizO.seqIDInner + " " + String.format("获取客户【%s】日期【%s】的密钥【%s】成功\r\n",
                tenant, Format.Date8Format.format(date), aeskey));
        return aeskey;
    }


    /**
     * 数据解密
     *
     * @param clientRespStr
     * @param p_bizO
     * @param aeskey
     * @return
     * @throws Exception
     */
    public String dataDecrypt(String clientRespStr, String aeskey, RequestNIO p_bizO, String charset) throws Exception {
        String encryptDataStr = StringHelper.getTagContext(clientRespStr, "encrypt");
        String respPlain = AESUtil.decrypt(encryptDataStr, aeskey, charset);

        p_bizO.sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + " " + p_bizO.seqIDInner + " " +
                String.format("使用客户【%s】的密钥【%s】解密成功\r\n", p_bizO.bankHeader.tenant, aeskey));
        p_bizO.sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + " " + p_bizO.seqIDInner + " " + "解密之后的结果：\r\n" + respPlain + "\r\n");
        return respPlain;
    }

    /**
     * 数据验签
     *
     * @param clientRespStr 响应报文
     * @param respPlain     签名原文
     * @param p_bizO
     * @param publicKey     对方公钥
     * @return
     * @throws Exception
     */
    public String dataVerify(String clientRespStr, String respPlain, RequestNIO p_bizO, PublicKey publicKey, String charset) throws Exception {
        String signtDataStr = StringHelper.getTagContext(clientRespStr, "signature");
        boolean verify = SignEncryptHelper.verify(respPlain.getBytes(charset), Base64.decodeBase64(signtDataStr), publicKey);
        if (verify) {
            p_bizO.sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + " " + p_bizO.seqIDInner + " " +
                    String.format("使用客户【%s】的公钥验签成功\r\n", p_bizO.bankHeader.tenant));
            return respPlain;
        } else {
            p_bizO.sbLog.append("\r\n" + Format.DateTimeSSSFormat.format(new Date()) + " " + p_bizO.seqIDInner + " " +
                    String.format("使用客户【%s】的公钥验签失败\r\n", p_bizO.bankHeader.tenant));
            throw new Exception(String.format("使用客户【%s】的公钥验签失败\r\n", p_bizO.bankHeader.tenant));
        }
    }


    /**
     * 数据签名验签
     *
     * @param respBodyPlain
     * @param aeskey
     * @param date
     * @param p_bizO
     * @return
     * @throws Exception
     */
    public String dataSignOrEncrypt(String respBodyPlain, String aeskey, Date date, RequestNIO p_bizO, String charset) throws Exception {
        StringBuilder reqXml = new StringBuilder();
        reqXml.append("<tenant>").append(p_bizO.bankHeader.tenant).append("</tenant>\r\n");
        //加密传密钥，不加密传明细,保证服务端能正常验签
        if (StringHelper.hasAnyChar(aeskey)) {
            String encryptBase64Str = AESUtil.encrypt(respBodyPlain, aeskey, charset);
            reqXml.append("<date>").append(Format.Date8Format.format(date)).append("</date>\r\n");
            reqXml.append("<encrypt>").append(encryptBase64Str).append("</encrypt>\r\n");
        } else {
            reqXml.append("<plain>").append(respBodyPlain).append("</plain>\r\n");
        }
        //数据签名
        byte[] signData = SignEncryptHelper.sign(respBodyPlain.getBytes(charset), FGBiz.dspCenter.dspSet.certConfig.ownPriKey);
        reqXml.append("<signature>").append(Base64.encodeBase64String(signData)).append("</signature>");
        return reqXml.toString();
    }

}
